package org.tgcloud.group.service.manager;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.tgcloud.group.core.*;
import org.tgcloud.group.core.ExportUtils.ExcelImport;
import org.tgcloud.group.core.ExportUtils.ExcelUtils;
import org.tgcloud.group.core.fileUtils.FileUtil;
import org.tgcloud.group.core.fileUtils.UpLoadFile;
import org.tgcloud.group.core.mapUtils.GeoUtils;
import org.tgcloud.group.core.mapUtils.TXMapUtils;
import org.tgcloud.group.core.mapUtils.data.LocationData;
import org.tgcloud.group.core.mapUtils.data.TXResultData;
import org.tgcloud.group.entity.Media;
import org.tgcloud.group.entity.MediaType;
import org.tgcloud.group.repository.MediaMapper;
import org.tgcloud.group.repository.MediaTypeMapper;
import org.tgcloud.group.service.task.ExcelPicTask;
import org.tgcloud.group.service.task.MediaTask;
import org.tgcloud.group.web.controller.dto.media.MediaAppBriefDTO;
import org.tgcloud.group.web.controller.dto.media.MediaDTO;
import org.tgcloud.group.web.controller.dto.media.MediaImportMsgDTO;
import org.tgcloud.group.web.controller.dto.media.MediaOtherMsgDTO;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


/**
 * @Author: zhy
 * @Created: 2025-02-11-下午2:30
 * @Description:
 */
@Service
public class MediaManageService {

    @Autowired
    private AsyncService asyncService;

    @Autowired
    private MediaMapper mediaMapper;

    @Autowired
    private MediaTypeMapper mediaTypeMapper;

    @Autowired
    private TXMapUtils txMapUtils;

    @Autowired
    private GeoUtils geoUtils;

    /**
     * 媒体类型
     * */

    public APPResultMessage getMediaTypeList(Integer pageNum, Integer pageSize, String keyword) {
        if (pageNum != null && pageSize != null){
            PageHelper.startPage(pageNum, pageSize);
            List<MediaType> dtos = mediaTypeMapper.selectManageList(keyword);
            PageInfo<MediaType> tables = new PageInfo<>(dtos);
            ResultMessage result = ResultMessage.builder().setList(tables.getList()).setAllPageNumber(tables.getPages()).setCount(tables.getTotal());
            APPResultMessage<Object, MediaType> message = APPResultMessage.getSuccessMessage();
            message.setResult(result);
            return message;
        }else {
            List<MediaType> dtos = mediaTypeMapper.selectManageList(keyword);
            ResultMessage result = ResultMessage.builder().setList(dtos);
            APPResultMessage<Object, MediaType> message = APPResultMessage.getSuccessMessage();
            message.setResult(result);
            return message;
        }
    }

    public APPResultMessage addMediaType(String name, String iconPath, Integer sort) {
        MediaType mediaTypeMsg = mediaTypeMapper.selectSameNameByName(name);
        if (mediaTypeMsg != null){
            return new APPResultMessage(6001, "媒体类型名称重复");
        }
        MediaType mediaType = new MediaType();
        mediaType.setName(name);
        mediaType.setIconPath(iconPath);
        mediaType.setStatus((short) 1);
        mediaType.setSort(sort);
        mediaTypeMapper.insertSelective(mediaType);
        return APPResultMessage.getSuccessMessage();
    }

    public APPResultMessage updateMediaType(int id, String name, String iconPath, Integer sort) {
        MediaType mediaTypeMsg = mediaTypeMapper.selectSameNameByName(name);
        if (mediaTypeMsg != null && mediaTypeMsg.getId() != id){
            return new APPResultMessage(6001, "媒体类型名称重复");
        }
        MediaType mediaType = new MediaType();
        mediaType.setId(id);
        mediaType.setName(name);
        mediaType.setIconPath(iconPath);
        mediaType.setSort(sort);
        mediaTypeMapper.updateByPrimaryKeySelective(mediaType);
        return APPResultMessage.getSuccessMessage();
    }

    public APPResultMessage delMediaType(int id) {
        mediaTypeMapper.updateStatusById(id, (short) 10);
        return APPResultMessage.getSuccessMessage();
    }


    /**
     * 媒体资源
     * */
    public APPResultMessage getMediaList(Integer pageNum, Integer pageSize, String keyword, Integer mediaType) {
        Map dataMap = new HashMap();
        JSONObject classTableByApiModelProperty = getClassTableByApiModelProperty(MediaOtherMsgDTO.class.getDeclaredFields());
        dataMap.put("classMap", classTableByApiModelProperty);
        JSONObject positionByApiModelProperty = getPositionByApiModelProperty(MediaOtherMsgDTO.class.getDeclaredFields());
        dataMap.put("positionMap", positionByApiModelProperty);
        JSONObject dataTypeByApiModelProperty = getDataTypeByApiModelProperty(MediaOtherMsgDTO.class.getDeclaredFields());
        dataMap.put("dataType", dataTypeByApiModelProperty);
        if (pageNum != null && pageSize != null){
            PageHelper.startPage(pageNum, pageSize);
            List<MediaDTO> dtos = mediaMapper.selectManageList(keyword, mediaType);
            PageInfo<MediaDTO> tables = new PageInfo<>(dtos);
            ResultMessage result = ResultMessage.builder().setList(tables.getList()).setAllPageNumber(tables.getPages()).setCount(tables.getTotal());
            result.setData(dataMap);
            APPResultMessage<Object, MediaDTO> message = APPResultMessage.getSuccessMessage();
            message.setResult(result);
            return message;
        }else {
            List<MediaDTO> dtos = mediaMapper.selectManageList(keyword, mediaType);
            ResultMessage result = ResultMessage.builder().setList(dtos);
            result.setData(dataMap);
            APPResultMessage<Object, MediaDTO> message = APPResultMessage.getSuccessMessage();
            message.setResult(result);
            return message;
        }
    }


    public APPResultMessage addMedia(String title, Integer mediaType, String address, String otherMsg) {
        Media media = new Media();
        media.setTitle(title);
        media.setMediaType(mediaType);
        media.setAddress(address);
        media.setOtherMsg(otherMsg);
        media.setOtherMsgClass(getClassTableByApiModelProperty(MediaOtherMsgDTO.class.getDeclaredFields()).toJSONString());
        media.setStatus((short) 1);
        mediaMapper.insert(media);
        return APPResultMessage.getSuccessMessage();
    }


    public APPResultMessage updateMedia(Integer id, String title, Integer mediaType, String address, String otherMsg) {
        Media media = new Media();
        media.setId(id);
        media.setTitle(title);
        media.setMediaType(mediaType);
        media.setAddress(address);
        media.setOtherMsgClass(getClassTableByApiModelProperty(MediaOtherMsgDTO.class.getDeclaredFields()).toJSONString());
        Media mediaMsg = mediaMapper.selectMsgById(id);
        MediaOtherMsgDTO dto = JSONObject.parseObject(otherMsg, MediaOtherMsgDTO.class);
        // 获取每个地方的经纬度
        // 判断地址是否有改变，如果有改变，那么需要重新获取经纬度 address和specificLocation字段用意一致
        if (StringUtil.isNotBlank(dto.getSpecificLocation()) && mediaMsg != null && (StringUtil.isBlank(mediaMsg.getAddress()) || !mediaMsg.getAddress().equals(address))){
            LocationData location = txMapUtils.getGDGeocoderToLocation(dto.getSpecificLocation());
            if (location != null && Objects.equals(location.getLat(), "0")){
                dto.setLongitude(location.getLng());
                dto.setLatitude(location.getLat());
                media.setLongitude(location.getLng());
                media.setLatitude(location.getLat());
                media.setAddress(dto.getSpecificLocation());
                otherMsg = JSONObject.toJSONString(dto);
            }
        }
        media.setOtherMsg(otherMsg);
        mediaMapper.updateByPrimaryKeySelective(media);
        return APPResultMessage.getSuccessMessage();
    }

    public APPResultMessage delMedia(int id) {
        mediaMapper.updateStatusById(id, (short) 10);
        return APPResultMessage.getSuccessMessage();
    }



    public JSONObject getClassTableByApiModelProperty(Field[] declaredFields){
        JSONObject classTable = new JSONObject();
        for (Field field : declaredFields) {
            // 设置可访问权限为true，以便可以访问私有字段
            field.setAccessible(true);
            // 检查字段是否有ApiModelProperty注解
            if (field.isAnnotationPresent(ApiModelProperty.class)) {
                ApiModelProperty apiModelValue = field.getAnnotation(ApiModelProperty.class);
                // 输出注解的值
                classTable.put(field.getName(), apiModelValue.value());
            }
        }
        return classTable;
    }

    public JSONObject getPositionByApiModelProperty(Field[] declaredFields){
        JSONObject classTable = new JSONObject();
        for (Field field : declaredFields) {
            // 设置可访问权限为true，以便可以访问私有字段
            field.setAccessible(true);
            // 检查字段是否有ApiModelProperty注解
            if (field.isAnnotationPresent(ApiModelProperty.class)) {
                ApiModelProperty apiModelValue = field.getAnnotation(ApiModelProperty.class);
                // 输出注解的值
                classTable.put(field.getName(), apiModelValue.position());
            }
        }
        return classTable;
    }

    public JSONObject getDataTypeByApiModelProperty(Field[] declaredFields){
        JSONObject classTable = new JSONObject();
        for (Field field : declaredFields) {
            // 设置可访问权限为true，以便可以访问私有字段
            field.setAccessible(true);
            // 检查字段是否有ApiModelProperty注解
            if (field.isAnnotationPresent(ApiModelProperty.class)) {
                ApiModelProperty apiModelValue = field.getAnnotation(ApiModelProperty.class);
                // 输出注解的值
                if (StringUtil.isNotBlank(apiModelValue.dataType())){
                    classTable.put(field.getName(), apiModelValue.dataType());
                }
            }
        }
        return classTable;
    }


    public APPResultMessage doImportMediaExcel(MultipartFile file) throws Exception{
        String fileName = StringUtil.generateOrderIdByName("Media_");
        File file1 = ExcelUtils.MultipartFileToFile(file, fileName);
        if (file1 == null){
            return new APPResultMessage(6001, "未找到该文件");
        }
        String filePath = file1.getPath();
        List<MediaImportMsgDTO> msgDTOList = EasyExcel.read(filePath).head(MediaImportMsgDTO.class).sheet().doReadSync();
        // 添加数据，因为数据量巨大，需要拆分进行添加
        doInsertMediaMsg(msgDTOList, fileName, filePath);
        return APPResultMessage.getSuccessMessage();
    }


    public void doInsertMediaMsg(List<MediaImportMsgDTO> msgDTOList, String fileName, String filePath) throws Exception{
        List<Media> mediaList = new ArrayList<>();
        for (int i = 0; i < msgDTOList.size(); i++){
            MediaImportMsgDTO dtoMsg = msgDTOList.get(i);
            MediaOtherMsgDTO dto = new MediaOtherMsgDTO();
            BeanUtils.copyProperties(dtoMsg, dto);
            // 图片赋值
            String pic = "pic_" + fileName + "_" + i;
            String picUrl = pic + ".png";
            dto.setExampleDiagram(ExcelUtils.doViewOSSPicPath(GlobalStatic.viewPicUrl + "/pic") + "/" + picUrl);

            Media media = new Media();
            media.setTitle(dto.getTitle());
            media.setStatus((short) 1);
            // 获取媒体类型
            if (StringUtil.isNotBlank(dto.getMediaType())){
                Integer mediaTypeId = null;
                MediaType mediaType = mediaTypeMapper.selectSameNameByName(dto.getMediaType());
                if (mediaType == null){
                    MediaType mediaTypeModel = new MediaType();
                    mediaTypeModel.setName(dto.getMediaType());
                    mediaTypeModel.setIconPath("https://checkorder-view.mejour.cn/mobile/images/choose_location.png");
                    mediaTypeModel.setStatus((short) 1);
                    mediaTypeMapper.insertSelective(mediaTypeModel);
                    mediaTypeId = mediaTypeModel.getId();
                }else {
                    mediaTypeId = mediaType.getId();
                }
                media.setMediaType(mediaTypeId);
            }
            media.setAddress(dto.getSpecificLocation());
            // 所有信息包装到otherMsg里
            media.setOtherMsgClass(getClassTableByApiModelProperty(MediaOtherMsgDTO.class.getDeclaredFields()).toJSONString());
            media.setOtherMsg(JSON.toJSONString(dto));
            mediaList.add(media);
        }
        // 对mediaList进行数据分片
        int batchSize = 10000;
        List<List<Media>> partitionedData = Lists.partition(mediaList, batchSize);
        ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        CountDownLatch latch = new CountDownLatch(partitionedData.size());
        for (final List<Media> chunk : partitionedData) {
            executor.submit(() -> {
                try {
                    mediaMapper.insertBatch(chunk);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    latch.countDown();
                }
            });
        }
        latch.await(); // 等待所有任务完成
        executor.shutdown();
        asyncService.doGetExcelPicByFilePath(filePath, fileName);
        asyncService.doGetLatAndLon();
    }


    public void doRefreshRedis() {
        RedisUtil.deleteObject(GeoUtils.GEO_KEY);
        List<MediaAppBriefDTO> appBriefDTOS = mediaMapper.selectAllTestList2();
        for (MediaAppBriefDTO dto : appBriefDTOS){
            double longitude = Double.parseDouble(dto.getLongitude());
            double latitude = Double.parseDouble(dto.getLatitude());
            geoUtils.geoAdd(dto.getId().toString(), longitude, latitude);
        }
    }

    public APPResultMessage delBatchMedia(Integer mediaType, String channelName) {
        List<Integer> ids = mediaMapper.selectListByMediaTypeAndChannelName(mediaType, channelName);
        for (Integer mediaId : ids) {
            geoUtils.geoDel(mediaId.toString());
        }
        mediaMapper.updateStatusByIds(ids, (short) 10);
        APPResultMessage message = APPResultMessage.getSuccessMessage();
        ResultMessage resultMessage = ResultMessage.builder().setData(ids.size());
        message.setResult(resultMessage);
        return message;
    }
}
